module sw.synchronize;
import std.string, std.stdio, sw.siteconfig, nazo.httpclient, nazo.file, std.uri, sw.utils, std.conv, sw.cgiinfo, nazo.date, nazo.sort;
alias std.uri.encode encode;
version(Wiki) import sw.wiki.commentlist, sw.wiki.pagelist, sw.wiki.recentlist, sw.wiki.dat, sw.wiki.preflist, sw.wiki.article;
version(Upload) import sw.upload.uploadlist;

version(Wiki){
void synchronizeWiki(SiteConfig* cfg, HttpClient client, string syncURI, string host, string path){
  writefln("*** Begin Synchronize Wiki ***");
  writef("Update Comment File...");
  client=new HttpClient(host);
  try{
    nazo.file.write(AllCommentList.getFileName,cast(string)client.download(path~"?mode=backup:wiki:comment",client.GET,null,exists(AllCommentList.getFileName)?getLastWriteTime(AllCommentList.getFileName):d_time.init));
    uint line;
    if(exists("comment.tmp")){
      line=.toUint((cast(string)read("comment.tmp")).replace("\n",""));
    }
    AllCommentList acl=new AllCommentList;
    Comment[] cmts=acl.getAllComments(line);
    for(Comment* cmt=&cmts[0];cmt<=&cmts[$-1];cmt++){
      CommentList cl=new CommentList(cmt.page);
      Article page=Article(cmt.page);
      if(cmt.op=="add"){
        cl.addComment(cmt,false);
        page.addCommentLength();
      }else if(cmt.op=="remove"){
        cl.removeComment(cmt.index,false);
        page.removeCommentLength();
      }
      line++;
    }
    nazo.file.write("comment.tmp",std.string.toString(line));
    writefln("Done");
  }catch(NotModifiedException e){
    writefln("Not Modified");
  }catch(Exception e){
    writefln(e);
  }
  writef("Update List File...");
  client=new HttpClient(host);
  try{
    nazo.file.write(PageList.getFileName,cast(string)client.download(path~"?mode=backup:wiki:list",client.GET,null,exists(PageList.getFileName)?getLastWriteTime(PageList.getFileName):d_time.init));
    writefln("Done");
  }catch(NotModifiedException e){
    writefln("Not Modified");
  }catch(Exception e){
    writefln(e);
  }
  writef("Update Recent File...");
  client=new HttpClient(host);
  try{
    nazo.file.write(RecentList.getFileName,cast(string)client.download(path~"?mode=backup:wiki:recent",client.GET,null,exists(RecentList.getFileName)?getLastWriteTime(RecentList.getFileName):d_time.init));
    writefln("Done");
  }catch(NotModifiedException e){
    writefln("Not Modified");
  }catch(Exception e){
    writefln(e);
  }
  if(!exists("dat"))mkdir("dat");
  RecentList rl=new RecentList;
  foreach_reverse(string line;rl){
    string title=line.split(" ")[1..$].join(" ");
    writef("Update %s...",title);
    try{
      client=new HttpClient(host);
      string filename=Dat.getFileName(titleToFileName(title));
      string uri = genURI(cfg, title, path ~ "index.cgi") ~ genURISep2(cfg);
      nazo.file.write(filename,client.download(uri~"mode=backup:wiki:dat",client.GET,null,exists(filename)?getLastWriteTime(filename):d_time.init));
      writef("Done ");
      client=new HttpClient(host);
      filename=PrefList.getFileName(titleToFileName(title));
      nazo.file.write(filename,client.download(uri~"mode=backup:wiki:pref",client.GET,null,exists(filename)?getLastWriteTime(filename):d_time.init));
      writefln("Done");
    }catch(NotModifiedException e){
      writefln("Not Modified");
      break;
    }catch(Exception e){
      writefln(e);
    }
  }
  writefln("*** End Synchronize Wiki ***");
}
}
version(Upload){
void synchronizeUpload(SiteConfig* cfg, HttpClient client, string syncURI, string host, string path){///FIXME: 未テスト。
  writefln("*** Begin Synchronize Upload ***");
  writef("Update List File...");
  client=new HttpClient(host);
  try{
    nazo.file.write(UploadList.getFileName,cast(string)client.download(path~"?mode=backup:upload:list",client.GET,null,exists(UploadList.getFileName)?getLastWriteTime(UploadList.getFileName):d_time.init));
    writefln("Done");
  }catch(NotModifiedException e){
    writefln("Not Modified");
  }catch(Exception e){
    writefln(e);
  }
  UploadList ul = new UploadList;
  string[] keys=nazo.sort.sort(ul.getList.keys,delegate uint(string key){return .toUint(ul.getList[key].split(":")[3]);});
  keys=keys.reverse;
  if(!exists("upload"))mkdir("upload");
  foreach(key; keys){
    writef("Update %s...", key);
    client=new HttpClient(host);
    string fpath="upload/"~encode(key).replace("/","%2F").replace(".","%2E")~".tmp";
    string uri;
    uri=path~"index.cgi?mode=upload:show&name="~encode(key);
    try{
      nazo.file.write(fpath,client.download(uri,client.GET,null,exists(fpath)?getLastWriteTime(fpath):d_time.init));
      writefln("Done");
    }catch(NotModifiedException e){
      writefln("Not Modified");
      break;
    }catch(Exception e){
      writefln(e);
    }
  }
  writefln("*** End Synchronize Upload ***");
}
}

void synchronize(SiteConfig* cfg){
  string syncURI=getSyncURI(cfg);
  writefln("Synchronize from "~syncURI);
  writefln("同期中に更新があった場合、一部のファイルが更新されなくなる事があります。");//原因も分かってるけどさてどうするか。
  string host=syncURI["http://".length..$];
  int index = host.find("/");
  if(index >= 0)
    host=host[0..index];
  string path=syncURI["http://".length+host.length..$];
  HttpClient client;
  writef("Checking CGI Information...");
  client=new HttpClient(host);
  string tmp = cast(string)client.download(path~"?mode=backup:info",client.GET);
  string[string] info;
  foreach(line;tmp.split(\n)){
    info[line.split(": ")[0]]=line.split(": ")[1];
  }
  auto ci = new CgiInfo;
  if(info["EnableOptions"] != ci.enableOptions){///FIXME: 未テスト
    writefln("Error: Mismatch enabled options");
    return;
  }
  writefln("OK");

  writef("Update Config File...");
  client=new HttpClient(host);
  try{
    nazo.file.write(cfg.fileName,cast(string)client.download(path~"?mode=backup:config",client.GET));
    cfg.reload();
    cfg.synchronizeURI=syncURI;
    cfg.flash();
    writefln("Done");
  }catch(NotModifiedException e){
    writefln("Not Modified");
  }catch(Exception e){
    writefln(e);
  }
  version(Wiki) synchronizeWiki(cfg, client, syncURI, host, path);
  version(Upload) synchronizeUpload(cfg, client, syncURI, host, path);
}
